home *** CD-ROM | disk | FTP | other *** search
- /*
-
- This file is a combination of :
- src/net/unix/unixnfc.c
- src/net/unix/netdrv.c
- src/net/unix/undrv.c
-
- netdrv & undrv compile to a stand-alone program with talk with unixnfc
- via a FIFO in /tmp, using a RPC-like scheme. This versions runs inside
- of a abuse and therefore is a bit simpler.
-
-
- */
- #include "idle.hpp"
- #include "demo.hpp"
- #include "macs.hpp"
- #include "specs.hpp"
- #include "level.hpp"
- #include "game.hpp"
- #include <stdio.h>
- #include "timing.hpp"
- #include "fileman.hpp"
- #include "netface.hpp"
-
- #include "gserver.hpp"
- #include "gclient.hpp"
- #include "dprint.hpp"
- #include "netcfg.hpp"
-
-
- extern char *symbol_str(char *name);
-
- #ifdef __WATCOMC__
- #define getlogin() "DOS user"
- #endif
-
-
- base_memory_struct *base; // points to shm_addr
- base_memory_struct local_base;
- net_address *net_server=NULL;
- extern int registered;
- net_protocol *prot=NULL;
- net_socket *comm_sock=NULL,*game_sock=NULL;
- extern char lsf[256];
- game_handler *game_face=NULL;
- int local_client_number=0; // 0 is the server
- join_struct *join_array=NULL; // points to an array of possible joining clients
- extern char *get_login();
- extern void set_login(char *name);
-
- int net_init(int argc, char **argv)
- {
- int i,x,db_level=0;
- base=&local_base;
-
- local_client_number=0;
-
- if (!main_net_cfg)
- main_net_cfg=new net_configuration;
-
-
- if (!registered) return 0;
-
- for (i=1;i<argc;i++)
- if (!strcmp(argv[i],"-nonet"))
- return 0;
- else if (!strcmp(argv[i],"-port"))
- {
- if (i==argc-1 || !sscanf(argv[i+1],"%d",&x) || x<1 || x>0x7fff)
- {
- dprintf("bad value following -port, use 1..32000\n");
- return 0;
- }
- else
- main_net_cfg->port=x;
- } else if (!strcmp(argv[i],"-net") && i<argc-1)
- {
- i++;
- strcpy(main_net_cfg->server_name,argv[i]);
- main_net_cfg->state=net_configuration::CLIENT;
- }
- else if (!strcmp(argv[i],"-ndb"))
- {
- if (i==argc-1 || !sscanf(argv[i+1],"%d",&x) || x<1 || x>3)
- {
- dprintf("bad value following -ndb, use 1..3\n");
- return 0;
- } else { db_level=x; }
- } else if (!strcmp(argv[i],"-server"))
- main_net_cfg->state=net_configuration::SERVER;
- else if (!strcmp(argv[i],"-min_players"))
- {
- i++;
- int x=atoi(argv[i]);
- if (x>=1 && x<=8)
- main_net_cfg->min_players=x;
- else dprintf("bad value for min_players use 1..8\n");
- }
-
-
- net_protocol *n=net_protocol::first,*usable=NULL; // find a usable protocol from installed list
- int total_usable=0;
- for (;n;n=n->next) // show a list of usables, just to be cute
- {
- dprintf("Protocol %s : ",n->installed() ? "Installed" : "Not_installed");
- dprintf("%s\n",n->name());
- if (n->installed())
- {
- total_usable++;
- usable=n;
- }
- }
-
- if (!usable) { dprintf("No network protocols installed\n"); return 0; }
- prot=usable;
- prot->set_debug_printing((net_protocol::debug_type)db_level);
- if (main_net_cfg->state==net_configuration::SERVER)
- set_login(main_net_cfg->name);
-
- comm_sock=game_sock=NULL;
- if (main_net_cfg->state==net_configuration::CLIENT)
- {
- dprintf("Attempting to locate server %s, please wait\n",main_net_cfg->server_name);
- char *sn=main_net_cfg->server_name;
- if (main_net_cfg->addr)
- net_server = main_net_cfg->addr->copy();
- else
- net_server=prot->get_node_address(sn,DEFAULT_COMM_PORT,0);
- if (!net_server) { dprintf(symbol_str("unable_locate")); exit(0); }
- dprintf("Server located! Please wait while data loads....\n");
- }
-
- fman=new file_manager(argc,argv,prot); // manages remote file access
- if (game_face)
- delete game_face;
- game_face=new game_handler;
- join_array=(join_struct *)jmalloc(sizeof(join_struct)*MAX_JOINERS,"join array");
- base->join_list=NULL;
- base->mem_lock=0;
- base->calc_crcs=0;
- base->get_lsf=0;
- base->wait_reload=0;
- base->need_reload=0;
- base->input_state=INPUT_COLLECTING;
- base->current_tick=0;
- base->packet.packet_reset();
-
- return 1;
- }
-
-
-
-
- int net_start() // is the game starting up off the net? (i.e. -net hostname)
- { return (main_net_cfg && main_net_cfg->state==net_configuration::CLIENT); }
-
-
-
- int kill_net()
- {
- if (game_face) delete game_face;
- game_face=new game_handler;
-
- if (join_array) jfree(join_array); join_array=NULL;
- if (game_sock) { delete game_sock; game_sock=NULL; }
- if (comm_sock) { delete comm_sock; comm_sock=NULL; }
- delete fman; fman=NULL;
- if (net_server) { delete net_server; net_server=NULL; }
- if (prot)
- {
-
- prot->cleanup();
- prot=NULL;
- return 1;
- } else return 0;
- }
-
- void net_uninit()
- {
- kill_net();
- }
-
-
- int NF_set_file_server(net_address *addr)
- {
- if (prot)
- {
- fman->set_default_fs(addr);
- net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
-
- if (!sock) { dprintf("set_file_server::connect failed\n"); return 0; }
- uchar cmd=CLIENT_CRC_WAITER;
- if ( sock->write(&cmd,1)!=1 )
- dprintf("set_file_server::writefailed\n");
- else
- if (sock->read(&cmd,1)!=1)
- {
- dprintf("set_file_server::read failed\n"); // wait for confirmation that crc's are written
- delete sock;
- return 0;
- }
- delete sock;
- return cmd;
- } else return 0;
- }
-
- int NF_set_file_server(char *name)
- {
- if (prot)
- {
- net_address *addr=prot->get_node_address(name,DEFAULT_COMM_PORT,0);
- if (addr)
- {
- int ret=NF_set_file_server(addr);
- delete addr;
- return ret;
- } else return 0;
- } else return 0;
- }
-
-
- int NF_open_file(char *filename, char *mode)
- {
- if (prot)
- return fman->rf_open_file(filename,mode);
- else return -2;
- }
-
-
- long NF_close(int fd)
- {
- if (prot)
- return fman->rf_close(fd);
- else return 0;
- }
-
- long NF_read(int fd, void *buf, long size)
- {
- if (prot)
- return fman->rf_read(fd,buf,size);
- else return 0;
- }
-
- long NF_filelength(int fd)
- {
- if (prot)
- return fman->rf_file_size(fd);
- else return 0;
- }
-
- long NF_seek(int fd, long offset)
- {
- if (prot)
- return fman->rf_seek(fd,offset);
- else return 0;
- }
-
- long NF_tell(int fd)
- {
- if (prot)
- return fman->rf_tell(fd);
- else return 0;
- }
-
-
- void service_net_request()
- {
- if (prot)
- {
- if (prot->select(0)) // anything happening net-wise?
- {
- if (comm_sock && comm_sock->ready_to_read()) // new connection?
- {
- net_address *addr;
-
- net_socket *new_sock=comm_sock->accept(addr);
- if (new_sock)
- {
- uchar client_type;
- if (new_sock->read(&client_type,1)!=1)
- {
- delete addr;
- delete new_sock;
- }
- else
- {
- switch (client_type)
- {
- case CLIENT_NFS :
- {
- delete addr;
- fman->add_nfs_client(new_sock);
- } break;
- case CLIENT_CRC_WAITER :
- {
- crc_man.write_crc_file(NET_CRC_FILENAME); // return 0 on failure
- client_type=1; // confirmation byte
- new_sock->write(&client_type,1);
- delete new_sock; // done with this socket now
- delete addr;
- } break;
- case CLIENT_LSF_WAITER : // wants to know which .lsp file to start with
- {
- uchar len=strlen(lsf);
- new_sock->write(&len,1);
- new_sock->write(lsf,len);
- delete new_sock;
- delete addr;
- } break;
- default :
- {
- if (!game_face || game_face->add_client(client_type,new_sock,addr)==0) // ask server or client to add new client
- {
- delete addr;
- delete new_sock;
- }
- } break;
- }
- }
- }
- }
- if (game_face && !game_face->process_net())
- {
- delete game_face;
- game_face=new game_handler;
- }
- fman->process_net();
- }
- }
- }
-
-
- int get_remote_lsf(net_address *addr, char *filename) // filename should be 256 bytes
- {
- if (prot)
- {
- net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
- if (!sock) return 0;
-
- uchar ctype=CLIENT_LSF_WAITER;
- uchar len;
-
- if (sock->write(&ctype,1)!=1 ||
- sock->read(&len,1)!=1 || len==0 ||
- sock->read(filename,len)!=len)
- {
- delete sock;
- return 0;
- }
-
- delete sock;
- return 1;
-
- } else return 0;
- }
-
- void server_check() { ; }
-
- int request_server_entry()
- {
- if (prot && main_net_cfg)
- {
- if (!net_server) return 0;
-
- if (game_sock) delete game_sock;
- dprintf("Joining game in progress, hang on....\n");
-
- int game_port = main_net_cfg->game_port;
-
- game_sock=prot->create_listen_socket(game_port,net_socket::SOCKET_FAST); // this is used for fast game packet transmission
- if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
- game_sock->read_selectable();
- main_net_cfg->game_port = game_port;
-
- net_socket *sock=prot->connect_to_server(net_server,net_socket::SOCKET_SECURE);
- if (!sock)
- {
- dprintf("unable to connect to server\n");
- return 0;
- }
-
- uchar ctype=CLIENT_ABUSE;
- ushort port=lstl(game_port),cnum;
-
- uchar reg;
- if (sock->write(&ctype,1)!=1 || // send server our game port
- sock->read(®,1)!=1) // is remote engine registered?
- { delete sock; return 0; }
-
- if (reg==2) // too many players
- {
- dprintf(symbol_str("max_players"));
- delete sock;
- return 0;
- }
-
- // maker sure the two games are both registered or unregistered or sync problems
- // will occur.
-
- if (reg && !registered)
- {
- dprintf(symbol_str("net_not_reg"));
- delete sock;
- return 0;
- }
-
- if (!reg && registered)
- {
- dprintf(symbol_str("server_not_reg"));
- delete sock;
- return 0;
- }
-
- char uname[256];
- if (get_login())
- strcpy(uname,get_login());
- else strcpy(uname,"unknown");
- uchar len=strlen(uname)+1;
- short nkills;
-
- if (sock->write(&len,1)!=1 ||
- sock->write(uname,len)!=len ||
- sock->write(&port,2)!=2 || // send server our game port
- sock->read(&port,2)!=2 || // read server's game port
- sock->read(&nkills,2)!=2 ||
- sock->read(&cnum,2)!=2 || cnum==0 // read player number (cannot be 0 because 0 is server)
- )
- { delete sock; return 0; }
-
- nkills=lstl(nkills);
- port=lstl(port);
- cnum=lstl(cnum);
-
- main_net_cfg->kills=nkills;
- net_address *addr=net_server->copy();
- addr->set_port(port);
-
- if (game_face)
- delete game_face;
- game_face=new game_client(sock,addr);
- delete addr;
-
- local_client_number=cnum;
- return cnum;
- } else return 0;
- }
-
- int reload_start()
- {
- if (prot && game_face)
- return game_face->start_reload();
- else return 0;
- }
-
- int reload_end()
- {
- if (prot && game_face)
- return game_face->end_reload();
- else return 0;
- }
-
-
- void net_reload()
- {
- if (prot)
- {
- if (net_server)
- {
- if (current_level)
- delete current_level;
- bFILE *fp;
-
- if (!reload_start()) return ;
-
- do { // make sure server saves the file
- fp=open_file(NET_STARTFILE,"rb");
- if (fp->open_failure()) { delete fp; fp=NULL; }
- } while (!fp);
-
- spec_directory sd(fp);
-
- spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
- if (!e)
- {
- the_game->show_help("This level is missing copyright information, cannot load\n");
- current_level=new level(100,100,"untitled");
- the_game->need_refresh();
- }
- else
- current_level=new level(&sd,fp,NET_STARTFILE);
-
- delete fp;
- base->current_tick=(current_level->tick_counter()&0xff);
-
- reload_end();
- } else if (current_level)
- {
-
- join_struct *join_list=base->join_list;
-
-
- while (join_list)
- {
-
- view *f=player_list;
- for (;f && f->next;f=f->next); // find last player, add one for pn
- int i,st=0;
- for (i=0;i<total_objects;i++)
- if (!strcmp(object_names[i],"START"))
- st=i;
-
- game_object *o=create(current_start_type,0,0);
- game_object *start=current_level->get_random_start(320,NULL);
- if (start) { o->x=start->x; o->y=start->y; }
- else { o->x=100; o->y=100; }
-
- f->next=new view(o,NULL,join_list->client_id);
- strcpy(f->next->name,join_list->name);
- o->set_controller(f->next);
-
- if (start)
- current_level->add_object_after(o,start);
- else
- current_level->add_object(o);
-
- view *v=f->next;
-
- join_list=join_list->next;
- }
- base->join_list=NULL;
- current_level->save(NET_STARTFILE,1);
- base->mem_lock=0;
-
-
- jwindow *j=eh->new_window(0,yres/2,-1,-1,new info_field(WINDOW_FRAME_LEFT,
- WINDOW_FRAME_TOP,
- 0,symbol_str("resync"),
- new button(WINDOW_FRAME_LEFT,
- WINDOW_FRAME_TOP+eh->font()->height()+5,ID_NET_DISCONNECT,
- symbol_str("slack"),NULL)),symbol_str("hold!"))
- ;
-
-
-
- eh->flush_screen();
- if (!reload_start()) return ;
-
- base->input_state=INPUT_RELOAD; // if someone missed the game tick with the RELOAD data in it, make sure the get it
-
- // wait for all client to reload the level with the new players
- do
- {
- service_net_request();
- if (eh->event_waiting())
- {
- event ev;
- do
- {
- eh->get_event(ev);
- if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
- {
- if (game_face)
- game_face->end_reload(1);
- base->input_state=INPUT_PROCESSING;
- }
-
- } while (eh->event_waiting());
-
- eh->flush_screen();
- } else
- {
- if (idle_man)
- idle_man->idle();
- }
-
- } while (!reload_end());
- eh->close_window(j);
- unlink(NET_STARTFILE);
-
- the_game->reset_keymap();
-
- base->input_state=INPUT_COLLECTING;
-
- }
- }
- }
-
-
- int client_number() { return local_client_number; }
-
-
- void send_local_request()
- {
-
- if (prot)
- {
- if (current_level)
- base->current_tick=(current_level->tick_counter()&0xff);
- if (game_face)
- game_face->add_engine_input();
- } else base->input_state=INPUT_PROCESSING;
-
- }
-
-
- void kill_slackers()
- {
- if (prot)
- {
- if (game_face && !game_face->kill_slackers())
- {
- delete game_face;
- game_face=new game_handler();
- }
- }
- }
-
- int get_inputs_from_server(unsigned char *buf)
- {
- if (idle_man)
- idle_man->idle_reset();
-
- if (prot && base->input_state!=INPUT_PROCESSING) // if input is not here, wait on it
- {
- time_marker start;
-
- int total_retry=0;
- jwindow *abort=NULL;
-
- while (base->input_state!=INPUT_PROCESSING)
- {
- if (!prot)
- {
- base->input_state=INPUT_PROCESSING;
- return 1;
- }
- service_net_request();
-
- time_marker now; // if this is taking to long, the packet was probably lost, ask for it to be resent
-
- if (now.diff_time(&start)>0.05)
- {
- if (idle_man)
- idle_man->idle();
- if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
- dprintf("(missed packet)");
-
- if (game_face)
- game_face->input_missing();
- start.get_time();
-
- total_retry++;
- if (total_retry==12000) // 2 minutes and nothing
- {
- abort=eh->new_window(0,yres/2,-1,eh->font()->height()*4,
- new info_field(WINDOW_FRAME_LEFT,
- WINDOW_FRAME_TOP,
- 0,symbol_str("waiting"),
- new button(WINDOW_FRAME_LEFT,
- WINDOW_FRAME_TOP+eh->font()->height()+5,ID_NET_DISCONNECT,
- symbol_str("slack"),NULL)),symbol_str("Error"));
- eh->flush_screen();
- }
- }
- if (abort)
- {
- if (eh->event_waiting())
- {
- event ev;
- do
- {
- eh->get_event(ev);
- if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
- {
- kill_slackers();
- base->input_state=INPUT_PROCESSING;
- }
- } while (eh->event_waiting());
-
- eh->flush_screen();
- }
- }
- }
-
- if (abort)
- {
- eh->close_window(abort);
- the_game->reset_keymap();
-
- }
- }
-
-
- memcpy(base->last_packet.data,base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size());
-
- int size=base->packet.packet_size();
- memcpy(buf,base->packet.packet_data(),size);
-
- base->packet.packet_reset();
- base->mem_lock=0;
-
- return size;
- }
-
- int become_server(char *name)
- {
- if (prot && main_net_cfg)
- {
-
- if (comm_sock) delete comm_sock;
-
- int port = main_net_cfg->port, gameport = main_net_cfg->game_port;
-
- comm_sock=prot->create_listen_socket(port,net_socket::SOCKET_SECURE); // this is used for incomming connections
- main_net_cfg->port = port;
-
- if (!comm_sock) { prot=NULL; return 0; }
- comm_sock->read_selectable();
- prot->start_notify(0x9090, name, strlen(name)); // should we define a new socket for notifiers?
-
- if (game_sock) delete game_sock;
- game_sock=prot->create_listen_socket(gameport,net_socket::SOCKET_FAST); // this is used for fast game packet transmission
- if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
- game_sock->read_selectable();
- main_net_cfg->game_port = gameport;
-
- if (game_face)
- delete game_face;
- game_face=new game_server;
- local_client_number=0;
- return 1;
- }
- return 0;
- }
-
- void read_new_views() { ; }
-
-
- void wait_min_players()
- {
- if (game_face)
- game_face->game_start_wait();
- }
-